home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / info-service / gopher / incoming / goform.shar / goform next >
Encoding:
Text File  |  1993-04-09  |  11.8 KB  |  394 lines

  1. #!/usr/local/bin/perl
  2. #
  3. # goform -- crude telnettable Gopher form fillout daemon
  4. #
  5. # History:
  6. # PASR 03/09/93    Original version (release 0.1) by Prentiss Riddle,
  7. #        riddle@rice.edu.
  8. # PASR 03/29/93    Use CRLF on output to user, to make Macs and PCs happy;
  9. #        explicitly send an IAC WONT ECHO so Mac telnet clients
  10. #        will know that they have to echo locally.
  11. # PASR 04/02/93 Added "Reply-To" handling.  Declared this version 0.2.
  12. #
  13. #-------------------------------------------------------------------------
  14. #
  15. # INSTALLATION:
  16. # The goform program should be executed from inetd with the name of the
  17. # form file as an argument.  In order to have multiple goform forms
  18. # available, each should be assigned a separate port.  An example SunOS
  19. # 4.1.2 installation:
  20. # Files installed:
  21. #     /foo/cwis/bin/goform        executable
  22. #     /foo/cwis/etc/widget.form    Widget Request form
  23. #     /foo/cwis/etc/suggest.form    Suggestion Box form
  24. # Added to /etc/services (be sure to make yp afterward):
  25. #    goform10003      10003/tcp           # gopher form: widget request
  26. #    goform10004      10004/tcp           # gopher form: suggestion box
  27. # Added to /etc/inetd.conf (be sure to HUP inetd afterward):
  28. #    goform10003      stream  tcp     nowait  nobody    /foo/cwis/bin/goform        goform /foo/cwis/etc/widget.form
  29. #    goform10004      stream  tcp     nowait  nobody    /foo/cwis/bin/goform        goform /foo/cwis/etc/suggest.form
  30. # FORMFILE FORMAT:
  31. #
  32. # The first few lines of the formfile specify header lines which will be
  33. # used to mail off the results after the form is filled out, as follows:
  34. #
  35. #    To: recipient-address
  36. #    Subject: subject-line
  37. #    Reply-To: return-address
  38. #
  39. # The recipient address must be fixed but the subject line and the return
  40. # address may contain field specifications in the form of a '$' character
  41. # followed by an integer.  These will be expanded to include the
  42. # user's answers to the correspondingly numbered questions.  The Reply-To
  43. # line is optional; if it is omitted, a "Reply-To:" line will appear in 
  44. # the mail header with no argument.  Note that the program doesn't do any
  45. # error checking of the address specified in the Reply-To field, so
  46. # recipients should use care in replying.
  47. #
  48. # The remainder of the formfile specifies the form to be filled out.
  49. #
  50. # Lines containing a '[' are interpreted as questions.  Characters following
  51. # the '[' are taken to be a default value for the answer.  Characters
  52. # preceding the '[' are taken to be a prompt.  If there is no prompt
  53. # preceding the '[', the question is taken to be a running essay questions
  54. # and multiple lines of input are accepted until a blank line or a line
  55. # consisting of a single '.' is read.
  56. #
  57. # Non-question lines in the formfile are displayed to the user and/or
  58. # displayed together with the user's answers in the results sent by mail:
  59. # -- Lines beginning in '>' are displayed to the user but not mailed.
  60. # -- Lines beginning in '<' are mailed but not displayed to the user.
  61. # -- Lines beginning in '#' are comments and are ignored.
  62. # -- Lines containing no '[' and not beginning in '>', '<' or '#' are both
  63. #    displayed to the user and mailed.
  64. #
  65. #
  66. # EXAMPLE FORMFILE:
  67. #
  68. # To: widgetmeister@foobar.edu
  69. # Subject: Widget request from $2 ($1)
  70. # Reply-To: $1
  71. # # Test form.  This is a comment.
  72. #                           WIDGET REQUEST FORM
  73. # >
  74. # >Widget Services supplies widgets only to registered students, faculty
  75. # >and staff of Foobar University.
  76. # >
  77. # >To pick up your widget go to Room 101 between the hours of 1-2 pm
  78. # >Monday through Wednesday.
  79. # Personal info (e-mail address, name, office address, extension):
  80. #   E-mail address: [
  81. #             Name: [
  82. #   Office address: [
  83. #        Extension: [
  84. # Widget shape (round, square, triangular -- CHOOSE ONE):
  85. #        Round: [n
  86. #       Square: [n
  87. #   Triangular: [n
  88. # Number of widgets desired: [1
  89. # What additional features would you like to see in a widget?
  90. # [
  91. # <--------------------------------------------------------------------
  92. # <                          FOR OFFICE USE ONLY
  93. # <
  94. # < Processed by: ____________________________   Date: ________________
  95. # < 
  96. # < Comments: _________________________________________________________
  97. # <--------------------------------------------------------------------
  98. #    
  99. #-------------------------------------------------------------------------
  100. # Global variables:
  101. #  $ReplyTo   "Reply-To:" line
  102. #  $Subject   "Subject:" line
  103. #  $To        "To:" line
  104. #  $def       are there any default answers in @ans?
  105. #  $formfile  name of the file from which form will be taken
  106. #  $mailer    mail delivery program
  107. #  $nans      number of answers in @ansindex (and possible answers in @ans)
  108. #  $nl        number of lines in @lines
  109. #  @ans       answers from user (may be predetermined defaults)
  110. #  @ansindex  table to look up Nth answer in @ans (since @ans is sparse)
  111. #  @lines     lines in form
  112. #  @question  array of flags: does this line (in @lines) ask a question?
  113. #  FORM       file handle for form file
  114.  
  115. #-------------------------------------------------------------------------
  116.  
  117. require("ctime.pl");
  118.  
  119. $mailer = "/bin/mail";
  120. $usage = "usage: goform formfile";
  121.  
  122. # Parse command-line arguments.
  123. die("$usage\n") unless ($#ARGV == 0);
  124. $formfile = $ARGV[0];
  125.  
  126. # Immediately flush all output to STDOUT.  Send an "IAC WONT ECHO" string
  127. # (per RFCs 1184 and 857) so the Mac client will know it has to echo text
  128. # locally.  Then throw away an initial line of input in order to dispose of
  129. # any remaining telnet protocol cruft.
  130. $| = 1;
  131. print("\377\374\001\n");            # IAC WONT ECHO
  132. print("Press return to begin:\r\n");
  133. $whatnow = <STDIN>;
  134. print("\r\n\r\n\r\n\r\n");
  135.  
  136. &parseform();
  137.  
  138. do {
  139.     &makepass();
  140.  
  141.     do {
  142.         print("\r\nSave/Cancel/Revise (s/c/r)? ");
  143.         $whatnow = <STDIN>;
  144.         $whatnow =~ tr/A-Z/a-z/;
  145.     } until($whatnow =~ /^\s*(s|save|c|cancel|r|revise)\s*$/);
  146.     if ($whatnow =~ /^\s*(c|cancel)\s*$/) {
  147.         print("Cancelling...")
  148.         &sleep(1);
  149.         exit(0);
  150.     }
  151.     print("\r\n\r\n\r\n\r\n");
  152. } until ($whatnow =~ /^\s*(s|save)\s*$/);
  153.  
  154. $Subject = &fixfields($Subject);
  155. $ReplyTo = &fixfields($ReplyTo);
  156.  
  157. &sendform();
  158.  
  159. #-------------------------------------------------------------------------
  160. # clean -- remove leading and final whitespace from a string.
  161. #
  162. # usage: $str = &clean($str);
  163.  
  164. sub clean {
  165.     local($str) = @_;
  166.     $str =~ s/^\s*//;
  167.     $str =~ s/\s*$//;
  168.     return($str);
  169. }
  170. #-------------------------------------------------------------------------
  171. # fixfields -- fill out "$N" items in Subject and Reply-To lines with
  172. #              corresponding answers
  173. #
  174. # Global variables used:  $ans  $ansindex
  175.  
  176. sub fixfields {
  177.     local($oldsubj) = @_;
  178.     local($l, $newsubj, $s);
  179.  
  180.     # Step through the Subject line.  When you find a "$n", substitute
  181.     # the corresponding answer field.
  182.     $newsubj = $oldsubj;
  183.     while ($newsubj =~ s/\$(\d*)/$ans[$ansindex[$1 - 1]]/e) {
  184.         # do nothing
  185.     }
  186.     return($newsubj);
  187. }
  188. #-------------------------------------------------------------------------
  189. # Make a pass through the form.
  190. #
  191. # Global variables used:
  192.  
  193. sub makepass {
  194.     local($char, $l, $resp);
  195.  
  196. #    # Remind the user how defaults work (unless this is the first
  197. #    # pass and there are none).
  198. #    if ($def) {
  199. #        print("\r\nNOTE:\r\n");
  200. #        print("To accept pre-defined values (in []), press return.\r\n");
  201. #        print("To delete a pre-defined value, type a space.\r\n\r\n");
  202. #    }
  203. #    $def = 1;
  204.  
  205.     # Loop through the lines in the form.
  206.     for ($l = 0; $l < $nl; $l++) {
  207.  
  208.         # Is there a question associated with this line?
  209.         if ($question[$l]) {
  210.             # Do we have a default answer for this question?
  211.             if ($ans[$l]) {
  212.                 printf("$lines[$l]<$ans[$l]> ");
  213.             } else {
  214.                 print("$lines[$l]");
  215.             }
  216.             # Is this a run-on essay question? (Is there a prompt?)
  217.             if ($lines[$l]) {
  218.                 # No, get a single answer.
  219.                 $resp = <STDIN>;
  220.                 $resp =~ s/[\r\n]*$//;
  221.                 $ans[$l] = &clean($resp) if ($resp);
  222.             } else {
  223.                 # Yes, it's a run-on question  -- accept
  224.                 # multiple lines in a single answer.
  225.                 print("\r\n") if ($ans[$l]);
  226.                 print("(Enter a blank line to finish.)\r\n");
  227.                 $resp = <STDIN>;
  228.                 $resp =~ s/[\r\n]*$//;
  229.                 if ($resp) {
  230.                     $ans[$l] = "";
  231.                     do {
  232.                         $ans[$l] .= &clean($resp) . " ";
  233.                         $resp = <STDIN>;
  234.                         $resp =~ s/[\r\n]*$//;
  235.                     } while ($resp);
  236.                 }
  237.             }
  238.         } else {
  239.             # This isn't a question -- print it unless it's
  240.             # intended only for the final mail.
  241.             $char = substr($lines[$l], 0, 1);
  242.             next if ($char eq "<" | $char eq '#');
  243.             if ($char eq ">") {
  244.                 print(substr($lines[$l], 1), "\r\n");
  245.             } else {
  246.                 print("$lines[$l]\r\n");
  247.             }
  248.         }
  249.     }
  250. }
  251. #-------------------------------------------------------------------------
  252. # mmddyy -- return date in the form "mm/dd/yy"
  253. #
  254. # Portability issue: we count on &ctime() to return the date in one of
  255. # the two following formats:
  256. #
  257. #       Wed Feb 24 10:42:22 1993
  258. #       Wed Feb 24 10:42:22 CST 1993
  259. #
  260. # If it doesn't, we're in trouble...
  261.  
  262. sub mmddyy {
  263.     local($date, $dd, $mm, $yy);
  264.  
  265.     $date = &ctime(time);
  266.     ($yy) = $date =~ /\s\d\d(\d\d)\s*$/;
  267.     $mm = &monthindex(substr($date, 4, 3));
  268.         $dd = substr($date, 8, 2);
  269.         $dd =~ s/ /0/;
  270.     return("$mm/$dd/$yy");
  271. }
  272. #--------------------------------------------------------------------------
  273. # monthindex -- given a three-character month abbreviation, return the
  274. #               corresponding integer "01" (January) to "12" (December)
  275. #
  276. # usage: $mm = &monthindex($monthstr);
  277. # error: return -1 in case of error;
  278.  
  279. sub monthindex {
  280.         local($monthstr) = @_;
  281.         local($mm);
  282.         $monthstr =~ tr/A-Z/a-z/;
  283.         $mm = index("janfebmaraprmayjunjulaugsepoctnovdec", $monthstr) / 3 + 1;
  284.         $mm = -1 if ($mm <= 0 || $mm > 12);
  285.         $mm = "0" . $mm if ($mm > 0 && $mm < 10);
  286.         return $mm;
  287. }
  288. #-------------------------------------------------------------------------
  289. # Parse the form.
  290. #
  291. # Global variables used:      FORM
  292. # Global variables modified:  $ReplyTo  $Subject  $To  $ans  $ansindex
  293. #                             $def  $formfile  $nans  $nl  $lines  $question
  294.  
  295. sub parseform {
  296.     local($_);
  297.  
  298.     open(FORM, "< $formfile") || die("Can't open form $formfile");
  299.  
  300.     $nans = 0;
  301.     $nl = 0;
  302.     $def = 0;
  303.     while ($_ = <FORM>) {
  304.         chop($_);
  305.     
  306.         # Discard comments.
  307.         next if (/^#/);
  308.     
  309.         # Find first instances of header lines.
  310.         if (!$ReplyTo && /^Reply-To:\s+(\S.*)/) {
  311.             $ReplyTo = $1;
  312.             next;
  313.         }
  314.         if (!$Subject && /^Subject:\s+(\S.*)/) {
  315.             $Subject = $1;
  316.             next;
  317.         }
  318.         if (!$To && /^To:\s+(\S.*)/) {
  319.             $To = $1;
  320.             next;
  321.         }
  322.     
  323.         # Determine which lines contain input markers ("[") and of
  324.         # those, which contain predetermined defaults.
  325.         if (/^(.*)\[(.*)\]?$/) {
  326.             $question[$nl] = 1;
  327.             $lines[$nl] = $1;
  328.             $ans[$nl] = $2;
  329.             $ansindex[$nans] = $nl;
  330.             $nans++;
  331.         } else {
  332.             $lines[$nl] = $_;
  333.         }
  334.         $nl++;
  335.     }
  336. }
  337. #-------------------------------------------------------------------------
  338. # sendform -- mail the resulting form off to the recipients defined in the
  339. #             "To:" line.
  340. #
  341. # Global variables used:  $ReplyTo  $Subject  $To  $ans  $lines  $mailer  $nl
  342.  
  343. format MAIL = 
  344. ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  345. $line
  346. ~~^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  347.   $line
  348. .
  349. sub sendform {
  350.     local($char, $l, $line, $s);
  351.  
  352.     print("Sending...\r\n");
  353.  
  354.     # Open the mail process
  355.     $To =~ s/'//g;            # sanitized for your protection
  356.     open(MAIL, "| $mailer '$To'")
  357.         || die("unable to open mailer $mailer to $To");
  358.  
  359.     print(MAIL "Subject: $Subject\r\nReply-To: $ReplyTo\r\n\r\n");
  360.  
  361.     print(MAIL "Date: " . &mmddyy() . "\r\n");
  362.  
  363.     for($l=0; $l<$nl; $l++) {
  364.         # Skip lines intended only for the user.
  365.         $char = substr($lines[$l], 0, 1);
  366.         next if ($char eq ">" | $char eq '#');
  367.         if ($char eq "<") {
  368.             # This line intended only for mail recipient.
  369.             $line = substr($lines[$l], 1);
  370.         } elsif ($lines[$l]) {
  371.             # Normal line -- may include an answer.
  372.             $line = $lines[$l] . $ans[$l];
  373.         } else {
  374.             # Indent lines with no question.
  375.             $line = "  " . $ans[$l];
  376.         }
  377.         write(MAIL);
  378.     }
  379.     close(MAIL);
  380. }
  381. #-------------------------------------------------------------------------
  382. # end of goform script
  383.